package com.qn.auth;

import com.qn.dto.UserTokenDTO;
import com.qn.util.JWTUtils;
import com.qn.util.ServletUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.Cookie;

/**
 * session 管理工具类
 *
 * @author Qning
 * @date 2022/05/13
 */
@Component
public class SessionManager {
    private static TokenDao tokenDao;

    @Autowired
    public void setTestService(TokenDao tokenDao) {
        SessionManager.tokenDao = tokenDao;
    }

    /**
     * 获取当前 TokenValue
     *
     * @return {@link String}
     */
    public static String getTokenValueNotCut() {
        String tokenValue;

        // 1. 尝试从 header 里读取
        tokenValue = ServletUtils.getRequest().getHeader(TokenDao.TOKEN_NAME);

        // 2. 尝试从 cookie 里读取
        if (tokenValue == null) {
            tokenValue = ServletUtils.getCookieValue(TokenDao.TOKEN_NAME);
        }

        // 3. 返回
        return tokenValue;
    }

    /**
     * 获取登录 id
     *
     * @return {@link Object}
     */
    public static Object getLoginId() {
        String tokenValueNotCut = getTokenValueNotCut();
        UserTokenDTO userTokenDTO = JWTUtils.parseToken(tokenValueNotCut);
        return userTokenDTO.getUid();
    }

    /**
     * 将 Token 保存到 [Cookie] 里
     *
     * @param cookieName    Cookie名称
     * @param tokenValue    token值
     * @param cookieTimeout Cookie存活时间(秒)
     */
    public static void setTokenValueToCookie(String cookieName, String tokenValue, int cookieTimeout) {
        Cookie cookie = new Cookie(cookieName, tokenValue);
        cookie.setMaxAge(cookieTimeout);
        cookie.setHttpOnly(true);
        cookie.setPath("/");

        ServletUtils.getResponse().addCookie(cookie);
    }

    /**
     * 删除 cookie
     *
     * @param cookieName Cookie名称
     */
    public static void deleteCookie(String cookieName) {
        setTokenValueToCookie(cookieName, "", 0);
    }

    /**
     * 登录
     *
     * @param userTokenDTO 登录信息
     */
    public static void login(UserTokenDTO userTokenDTO) {
        // 生成 token
        String token = JWTUtils.generateToken(userTokenDTO);

        String key = TokenDao.TOKEN_REDIS_KEY + token;
        // 存入 token 至 redis
        tokenDao.setObject(key, token, TokenDao.DEFAULT_EXPIRE);

        // 存入 token 至 cookie
        setTokenValueToCookie(TokenDao.TOKEN_NAME, token, TokenDao.COOKIE_EXPIRE);
    }

    /**
     * 注销
     */
    public static void logout() {
        // 如果连 token 都没有，那么无需执行任何操作
        String tokenValueNotCut = getTokenValueNotCut();
        if (tokenValueNotCut == null) {
            return;
        }

        // 清除 cookie
        deleteCookie(TokenDao.TOKEN_NAME);

        // 清除这个 token 相关信息
        logoutByTokenValue(tokenValueNotCut);
    }

    /**
     * 会话注销，根据指定 Token
     *
     * @param tokenValue 指定 token
     */
    public static void logoutByTokenValue(String tokenValue) {
        // 删除 token
        String key = TokenDao.TOKEN_REDIS_KEY + tokenValue;
        tokenDao.deleteObject(key);
    }

    /**
     * token 续期
     *
     * @param tokenValue token值
     */
    public static void renewalToken(String tokenValue) {
        // redis 中 token 续期
        String key = TokenDao.TOKEN_REDIS_KEY + tokenValue;
        tokenDao.updateObjectTimeout(key, TokenDao.DEFAULT_EXPIRE);

        // cookie 中 token 续期
        setTokenValueToCookie(TokenDao.TOKEN_NAME, tokenValue, TokenDao.COOKIE_EXPIRE);
    }

    /**
     * 获取 token 的剩余存活时间 (单位: 秒)
     *
     * @param tokenValue token值
     */
    public static Long getTokenExpiration(String tokenValue) {
        String key = TokenDao.TOKEN_REDIS_KEY + tokenValue;
        return tokenDao.getObjectTimeout(key);
    }
}
